package com.lei.study.cds.unit4;

import com.lei.study.cds.unit2.MvelCalculateTools;
import org.apache.commons.lang3.StringUtils;
import org.mvel2.MVEL;
import org.mvel2.ParserContext;

import java.io.Serializable;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author 伍磊
 */
public class Parse {

    public static void main(String[] args) {
        String express = "#avg# ( ( #t-2#{CASH} / #t-2#{TASSET} ), ( #t-1#{CASH} / #t-1#{TASSET} ), ({CASH} / {TASSET} )) + " +
                "(#t-2#{STLOAN}  + #t-1#{STLOAN}  + {STLOAN} ) / (#t-2#{REV}  + #t-1#{REV}  + {REV} ) ";

        // 1 替换TYPE = 10 包含常用语法替换
        String str = step1(express);

        // 2 处理参数
        // 组装传递参数
        List<String> params = new ArrayList<>();
        params.add("CASH");
        params.add("TASSET");
        params.add("STLOAN");
        params.add("REV");

        // 获取需要参与计算的项目 包含基础与衍生 其中项目中带有#T#会将此项目添加到计算项目中
        List<String> wholeParams = handlerParam(params, str);

        // 3 替换ORDER_TYPE = 20
        // 将#t-1# #t-2#转换为对应的
        str = str.replaceAll("#t-1#", "R1T0SEP0");
        str = str.replaceAll("#t-2#", "R2T0SEP0");

        List<String> newParams = replaceParams(wholeParams);

        // 4 处理参数中的衍生参数
        // 假设REV为衍生项目 实际需根据params获取到每个项目是否为衍生项目 若是衍生项目，那么需要进行特殊处理
        String s = handlerDerivative(params, newParams, str);
        System.out.println(s);
        System.out.println(newParams);
        // 5 入库

        // 6 入redis

        // 7 计算
        Map<String, Object> map = new HashMap<>();
        newParams.forEach(param -> map.put(param, new BigDecimal("0.01")));

        System.out.println("计算结果-----------------");

        ParserContext parserContext = MvelCalculateTools.initParse();
        Serializable compiled = MVEL.compileExpression(s, parserContext);
        Object o = MVEL.executeExpression(compiled, map);
        System.out.println(o);
    }

    private static List<String> replaceParams(List<String> wholeParams) {

        List<String> newParams = new ArrayList<>();
        // 替换参数
        wholeParams.forEach(param -> {
            param = param.replaceAll("#t-1#", "R1T0SEP0");
            param = param.replaceAll("#t-2#", "R2T0SEP0");
            newParams.add(param);
        });
        return newParams;
    }

    private static String handlerDerivative(List<String> params, List<String> wholeParams, String str) {
        // todo 假定REV为衍生项目 且此衍生项目计算公式为 REV = A1T0SEP0REVX + REVZ

        // 1 为衍生项目REV的参数
        List<String> rev = wholeParams.parallelStream()
                .filter(s -> s.contains("REV"))
                .collect(Collectors.toList());

        // 2 判断此衍生项目是否包含分隔符
        for (String re : rev) {
            if (re.contains("0SEP0")) {
                // 包含分隔符 则进行替换

                // 1 获取到参与此公式计算的全部参数 参数必须为基础项目
                List<String> basicParams = new ArrayList<>();
                basicParams.add("A1T0SEP0REVX");
                basicParams.add("REVZ");

                List<String> newBasicParams = new ArrayList<>();

                // 2 将re时间参数融合到基础公式的参数中
                // 公式
                String replace = "A1T0SEP0REVX + REVZ";
                String s = StringUtils.substringBefore(re, "T0SEP0");
                String type = s.substring(0, 1);
                String num = s.substring(1);
                int i = Integer.parseInt(num);

                // 变更map
                Map<String, String> map = new HashMap<>();
                for (String basicParam : basicParams) {
                    if (basicParam.contains("0SEP0")) {
                        String realParam = StringUtils.substringAfterLast(basicParam, "0SEP0");

                        // 含有时间函数
                        String s1 = StringUtils.substringBefore(basicParam, "T0SEP0");
                        String type1 = s1.substring(0, 1);
                        String num1 = s1.substring(1);
                        int j = Integer.parseInt(num1);

                        if (type.equals(type1)) {
                            // 相加
                            int b = i + j;
                            map.put(basicParam, type + b + "T0SEP0" + basicParam);
                            replace = replace.replace(basicParam, type + b + "T0SEP0" + realParam);
                            newBasicParams.add(type + b + "T0SEP0" + realParam);
                        } else {
                            // 不同
                            if ("A".equals(type)) {
                                // 基础项目是减少 外面是增加
                                int x = i - j;
                                if (x > 0) {
                                    map.put(basicParam, type + x + "T0SEP0" + basicParam);
                                    replace = replace.replace(basicParam, type + x + "T0SEP0" + realParam);
                                    newBasicParams.add(type + x + "T0SEP0" + realParam);
                                } else if (x == 0) {
                                    map.put(basicParam, basicParam);
                                    replace = replace.replace(basicParam, realParam);
                                    newBasicParams.add(realParam);
                                } else {
                                    map.put(basicParam, type1 + (j - i) + "T0SEP0" + basicParam);
                                    replace = replace.replace(basicParam, type1 + (j - i) + "T0SEP0" + realParam);
                                    newBasicParams.add(type1 + (j - i) + "T0SEP0" + realParam);
                                }
                            } else {
                                // 基础项目是增加 外面是减少
                                int x = j - i;
                                if (x > 0) {
                                    map.put(basicParam, type1 + x + "T0SEP0" + basicParam);
                                    replace = replace.replace(basicParam, type1 + x + "T0SEP0" + realParam);
                                    newBasicParams.add(type1 + x + "T0SEP0" + realParam);
                                } else if (x == 0) {
                                    map.put(basicParam, basicParam);
                                    replace = replace.replace(basicParam, realParam);
                                    newBasicParams.add(realParam);
                                } else {
                                    map.put(basicParam, type + (i - j) + "T0SEP0" + basicParam);
                                    replace = replace.replace(basicParam, type + (i - j) + "T0SEP0" + realParam);
                                    newBasicParams.add(type + (i - j) + "T0SEP0" + realParam);
                                }
                            }
                        }
                    } else {
                        // 没有时间函数
                        replace = replace.replace(basicParam, s + "T0SEP0" + basicParam);
                        map.put(basicParam, s + "T0SEP0" + basicParam);
                        newBasicParams.add(s + "T0SEP0" + basicParam);
                    }

                }

                replace = replace.replaceAll("(.{1})","$1@_@");
                // 删除原param 将新的替换
                str = str.replaceAll(re, "(" + replace + ")");

                // 替换参数
                wholeParams.remove(re);
                wholeParams.addAll(newBasicParams);
            } else {
                // 不包含分隔符 直接替换
                // todo
                str = str.replaceAll(re, "(" + "A1T0SEP0REVX + REVZ" + ")");
                wholeParams.remove(re);
                wholeParams.add("A1T0SEP0REVX");
                wholeParams.add("REVZ");
            }
        }
        return str.replaceAll("@_@", "");
    }

    private static List<String> handlerParam(List<String> params, String str) {
        List<String> newParams = new ArrayList<>();
        params.forEach(param -> {
            String old = str;
            String newParam = "#" + param;
            while (old.contains(newParam)) {
                String x = StringUtils.substringAfterLast(StringUtils.substringBefore(old, newParam), "#");
                newParams.add("#" + x + newParam);
                old = StringUtils.substringAfter(old, newParam);
            }
            if (old.contains(param)) {
                newParams.add(param);
            }
        });
        return newParams;
    }

    private static String step1(String express) {
        // 1 去除空格
        express = express.trim();

        // 2 去除 {}
        express = express.replaceAll("\\{", "");
        express = express.replaceAll("}", "");

        System.out.println(express);

        System.out.println("--------------");

        // 3 将And转换为 &&
        express = express.replaceAll("And", "&&");
        System.out.println(express);

        System.out.println("--------------");

        // 4 将此方法使用的函数的#去除
        express = express.replaceAll("#avg#", "AVG");
        System.out.println(express);

        System.out.println("--------------");

        return express;
    }
}
